package main

import (
	"context"
	"fmt"
	"github.com/360EntSecGroup-Skylar/excelize"
	"go.manyji.com/lib/log"
	"go.manyji.com/lib/util/convert"
	"reflect"
	"strings"
	"time"
)

func (a *data_UserRecords) Query(ctx context.Context, uid uint64, pp PaginationParam, queryConditions []string) interface{} {

	queryConditions = append(queryConditions, []string{
		"user_op_record.deleted = 0",
		fmt.Sprintf("user_op_record.leader_id = %v", uid),
	}...)

	var (
		condition = fmt.Sprintf(`
  INNER JOIN user ON user.id = user_op_record.account_id AND user.deleted = 0 AND user.role_id = %v
WHERE %v ORDER BY user_op_record.create_at DESC`, (&data_Role{}).GetChannelAgentRole().ID, strings.Join(queryConditions, " AND "))
		queryCountSQL = fmt.Sprintf(`
	SELECT 
	      COUNT(*)
	FROM user_op_record
	%v
`, condition)
		querySQL = fmt.Sprintf(`
SELECT
  user_op_record.id AS id,
  user_op_record.task_name AS task_name,
  user_op_record.business_type_name AS business_type_name,
  user_op_record.op_type_name AS op_type_name,
  user_op_record.points_consume_total AS points_consume_total,
  user_op_record.points_consume_account AS points_consume_account,
  user_op_record.points_consume_gift AS points_consume_gift,
  user_op_record.recharge_points AS recharge_points,
  user_op_record.bonus_points AS bonus_points,
  user_op_record.refund_points AS refund_points,
  user_op_record.residual_points AS residual_points,
  user_op_record.agent_points AS agent_points,
  user_op_record.account_id AS account_id,
  user_op_record.sieve_source_name AS sieve_source_name,
  user_op_record.leader_id AS leader_id,
  user_op_record.leader_name AS leader_name,
  user_op_record.creator AS creator,
  user_op_record.create_at AS create_at,
  user_op_record.updated_at AS updated_at,
  user_op_record.deleted AS deleted,
  user.account AS creator_name
FROM user_op_record
%v %v 
`, condition, fmt.Sprintf(" LIMIT %v OFFSET %v", pp.PageSize, (pp.PageIndex-1)*pp.PageSize))
	)

	log.Info("query sql ", querySQL)
	respCount, err := db.QueryRaw(ctx, queryCountSQL, QueryCount{})
	if err != nil {
		return err
	}

	if respCount == nil {
		return nil
	}

	count := respCount[0].(*QueryCount).Count

	respTaskList, err := db.QueryRaw(ctx, querySQL, QueryUserOpRecordResp{})
	if err != nil {
		return err
	}

	ret := map[string]interface{}{
		"list":  respTaskList,
		"total": count,
	}

	if ret != nil {

		var (
			t = QueryUserOpRecordResp{}
		)
		for _, v := range ret["list"].([]interface{}) {

			respRecord := v.(*QueryUserOpRecordResp)
			t.PointsConsumeTotal += respRecord.PointsConsumeTotal
			t.PointsConsumeAccount += respRecord.PointsConsumeAccount
			t.PointsConsumeGift += respRecord.PointsConsumeGift
			t.RechargePoints += respRecord.RechargePoints
			t.BonusPoints += respRecord.BonusPoints
			t.RefundPoints += respRecord.RefundPoints
			t.ResidualPoints += respRecord.ResidualPoints
			t.AgentPoints += respRecord.AgentPoints
		}

		ret["all"] = map[string]interface{}{
			"points_consume_total":   t.PointsConsumeTotal,
			"points_consume_account": t.PointsConsumeAccount,
			"points_consume_gift":    t.PointsConsumeGift,
			"recharge_points":        t.RechargePoints,
			"bonus_points":           t.BonusPoints,
			"refund_points":          t.RefundPoints,
			"residual_points":        t.ResidualPoints,
			"agent_points":           t.AgentPoints,
		}
	}

	return ret
}

func (a *data_UserRecords) addQueryResponseSeq(p PaginationParam, req map[string]interface{}) interface{} {

	if req != nil {

		var enable bool
		if _, ok := req["total"]; ok {
			if _, ok := req["list"]; ok {
				enable = true
			}
		}
		if enable {
			var (
				indexStart = 1
				total      = req["total"].(uint64)
			)

			for i, _ := range req["list"].([]interface{}) {

				//resp := v.(*schemaCustomer.RechargeQueryRsp)
				seqNo := int(total) - (p.PageSize*(p.PageIndex-1) + (int(i) + 1)) + indexStart
				//seqNo := (p.PageSize*(p.PageIndex-1) + (int(i) + 1)) + autoIndexStart
				//req.(map[string]interface{})["list"].([]interface{})[i].(*schemaCustomer.UserQueryRsp).Seq = int64(seqNo)
				req["list"].([]interface{})[i].(*DailyRechargeQueryResp).SeqNo = int64(seqNo)
			}
		}
	}

	return req
}

func (a *data_UserRecords) Export(ctx context.Context, item map[string]interface{}) interface{} {

	queryConditions := []string{
		"user_op_record.deleted = 0",
		fmt.Sprintf("user_op_record.id IN (%v)", strings.Join(strings.Split(item["ids"].(string), "|"), ",")),
	}
	var (
		condition = fmt.Sprintf(`
  INNER JOIN user ON user.id = user_op_record.account_id AND user.deleted = 0 AND user.role_id = %v
WHERE %v ORDER BY user_op_record.create_at DESC`, (&data_Role{}).GetChannelAgentRole().ID, strings.Join(queryConditions, " AND "))
		querySQL = fmt.Sprintf(`
SELECT
  user_op_record.id AS id,
  user_op_record.task_name AS task_name,
  user_op_record.business_type_name AS business_type_name,
  user_op_record.op_type_name AS op_type_name,
  user_op_record.points_consume_total AS points_consume_total,
  user_op_record.points_consume_account AS points_consume_account,
  user_op_record.points_consume_gift AS points_consume_gift,
  user_op_record.recharge_points AS recharge_points,
  user_op_record.bonus_points AS bonus_points,
  user_op_record.refund_points AS refund_points,
  user_op_record.residual_points AS residual_points,
  user_op_record.account_id AS account_id,
  user_op_record.leader_id AS leader_id,
  user_op_record.leader_name AS leader_name,
  user_op_record.creator AS creator,
  user_op_record.create_at AS create_at,
  user_op_record.updated_at AS updated_at,
  user_op_record.deleted AS deleted,
  user.account AS creator_name
FROM user_op_record
%v
`, condition)
	)

	resp, err := db.QueryRaw(ctx, querySQL, QueryUserOpRecordResp{})
	if err != nil {
		return err
	}

	selectedItems := []string{
		"id",
		"business_type_name",
		"op_type_name",
		"points_consume_total",
		"points_consume_gift",
		"recharge_points",
		"bonus_points",
		"refund_points",
		"residual_points",
		"creator_name",
		//"creator_role_name",
		"create_at",
	}
	req := a.export(ctx, resp, 1, strings.Join(selectedItems, "|"))
	if req != nil {
		if _, ok := req.(error); ok {
			return req
		}
	}

	return req
}

func (a *data_UserRecords) export(ctx context.Context, req interface{}, funcTy int, selectedItems string) interface{} {

	var (
		xlsx       = excelize.NewFile()
		categories = map[string]string{
			"A1": "序号",
			"B1": "业务类型",
			"C1": "操作类型",
			"D1": "消费积分",
			"E1": "赠送消费积分",
			"F1": "充值积分",
			"G1": "充值赠送积分",
			"H1": "退款积分",
			"I1": "剩余积分",
			"J1": "创建人",
			//"K1": "创建人角色",
			//"L1": "创建时间",
			"K1": "创建时间",
		}
		selectedItemMap = make(map[string]int)
		colWidths       = map[string]float64{"A": 8, "B": 22, "C": 18, "D": 10, "E": 10, "F": 10, "G": 10, "H": 10, "I": 10, "J": 12, "K": 12, "L": 20}
	)

	for key, value := range categories {
		xlsx.SetCellValue("Sheet1", key, value)
		_style, err := xlsx.NewStyle(`{"fill":{"type":"pattern","color":["#EEECE1"],"pattern":1},"alignment":{"horizontal":"center","vertical":"center"},"font":{"bold":true,"family":"宋体","size":10}}`)
		if err == nil {
			xlsx.SetCellStyle("Sheet1", key, key, _style)
		}
	}

	xlsx.SetRowHeight("Sheet1", 1, 20)

	for k, v := range colWidths {
		xlsx.SetColWidth("Sheet1", k, k, v)
	}

	for i, v := range strings.Split(fmt.Sprintf("%v", selectedItems), "|") {
		selectedItemMap[v] = i
	}

	p := map[string]struct{}{
		"points_consume_total": {},
		"points_consume_gift":  {},
		"recharge_points":      {},
		"bonus_points":         {},
		"refund_points":        {},
		"residual_points":      {},
	}
	for index, vv := range req.([]interface{}) {

		var (
			columIndex  = 'A'
			columOffset = 1
		)

		for kkk, vvv := range Struct2Map(vv, "json") {

			if len(selectedItemMap) > 0 {
				if i, ok := selectedItemMap[kkk]; !ok {
					continue
				} else {
					columOffset = i
				}
			}

			cell := fmt.Sprintf("%c", int(columIndex)+columOffset) + convert.ToString(index+2)

			if reflect.TypeOf(vvv).Kind() == reflect.Ptr {
				vOf := reflect.ValueOf(vvv)
				if vOf.IsNil() {
					vvv = ""
				} else {
					vvv = vOf.Elem()
				}
			}

			if kkk == "create_at" {
				vvv = Format(vvv.(int64))
			}

			if _, ok := p[kkk]; ok {
				vvv = Decimal(float64(vvv.(uint64))/10000.0, 5)
			}

			xlsx.SetCellValue("Sheet1", cell, vvv)
		}

		xlsx.SetRowHeight("Sheet1", index+2, 18)
	}

	xlsx.SetSheetName("Sheet1", "第一页")

	fileName, filePath := a.getExportPath(convert.ToString(time.Now().UnixMilli())+".csv", 1)
	err := xlsx.SaveAs(fileName)
	if err != nil {
		return nil
	}

	req = filePath

	return req
}

func (a *data_UserRecords) getExportPath(fileName string, bizTy int) (string, string) {

	var (
		bizTyMap = map[int]string{
			1: "user_op_record",
		}
	)

	relativePath := fmt.Sprintf("%v/export/%v", bizTyMap[bizTy], fileName)

	return GetFilePath(
		fmt.Sprintf("%v/%v",
			FileStorage,
			relativePath),
	), relativePath
}
